(* Time-stamp: <modified the 31/10/2024 (at 12:03) by Erwan Jahier> *)

(* Authors: Antony Zahran, Léandre Lacourt

   Generates a yaml file meant to be processed by lustre-mt
   (cf lv6 -2cmt cli).
*)

let dbg = (Lv6Verbose.get_flag "mt")

open Printf
(*open Soc2cIdent*)
open SocNameC
open Soc

(*  Not the  best complexity  for such  a function.  To use  on small
   lists.  Well, here the size of  the list corresponds to the number
    of tasks, that should not be huge (should it?)

    List.sort_uniq would be more efficient, but its sorts. is it ok?

*)
let _nodupl = List.fold_left (fun acc x -> if List.mem x acc then acc else x::acc) []
let nodupl = List.sort_uniq compare

let get_tasks_soc : Soc.tbl -> Soc.t -> task_type list=
  fun stbl soc ->
  List.map (fun (_tname,tsk) ->
      let (n, _, _) = tsk in
      let tsoc = SocUtils.find_nolxm tsk stbl in
      let (var_ins, var_outs) = tsoc.profile in
      let mem = tsoc.memory <> No_mem in
      {
        name = n;
        var_in = var_ins; (*List.map (var_expr_to_index all_vars) args_in;*)
        var_out = var_outs; (*List.map (var_expr_to_index all_vars) args_out*)
        memory = mem
      }
    )
    soc.tasks


let pinfo = Lv6Verbose.profile_info
let pverb str = Lv6Verbose.exe ~flag:dbg (fun () -> (Printf.printf "#MT: %s\n%!" str))


let (f : Soc.key -> Soc.tbl -> string -> unit) = fun sk stbl basename ->
  pinfo "Soc2yaml\n";
  let main_soc = SocUtils.find (Lxm.dummy "dfsdf") sk stbl in
  pverb "Soc2yaml: SocNameC.get_all_soc\n";
  let socs = (SocNameC.get_all_soc main_soc stbl) @ [main_soc]  in
  pverb "Soc2yaml: get_tasks_soc\n";
  let tasks = List.map (get_tasks_soc stbl) socs |> List.flatten |> nodupl in
  let yaml_file = open_out (basename ^ ".yml") in

  let (var2yaml : Soc.var -> string) = fun var ->
    let (name, var_type) = var in
    let var_type_str0, var_type_str1 = Soc2cUtil.data_type_to_c_pair var_type in
    let s = "        - name: \"" ^ name
            ^ "\"\n          type: \"" ^ var_type_str0
            ^ "\"\n          type_end: \"" ^ var_type_str1
            ^ "\"\n" in
    s
  in

  let (memory2string : bool -> string) = fun mem ->
    match mem with
    | true -> "true"
    | false -> "false"
  in

  let (tasks2yaml : task_type -> unit) = fun task ->
    let name = String.concat "_" (Str.split (Str.regexp "::") task.name) in
    let s_vi = String.concat "" (List.map var2yaml task.var_in) in
    let s_vo = String.concat "" (List.map var2yaml task.var_out) in
    let mem = memory2string task.memory in
    let s = "  - para_node: "
            ^ "\n      name: \"" ^ name
            ^ "\"\n      var_in:\n" ^ s_vi
            ^ "      var_out:\n" ^ s_vo
            ^ "      memory: " ^ mem
            ^ "\n"
    in
    fprintf yaml_file "%s" s
  in

  let (main2yaml : unit -> unit) = fun () ->
    let (name, _, _) = main_soc.key in
    let main_name = Str.replace_first (Str.regexp "::") "_" name in
    let s = "main_node: " ^ main_name in
    fprintf yaml_file "\n%s" s
  in

  fprintf yaml_file "all_para_nodes:\n";
  pverb "Soc2yaml: tasks2yaml\n";
  List.iter tasks2yaml tasks;
  pverb "Soc2yaml: main2yaml\n";
  main2yaml ();
  pverb "Soc2yaml: done\n";
  close_out yaml_file;
  let s = List.length tasks in
  printf "%s.yml file created (it contains %d task definition%s)\n%!"
    basename s (if s <= 1 then "" else "s")
